//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Diagnostics.Contracts;
using OpenLS.Spreadsheet.Expressions;

namespace OpenLS.Spreadsheet.Formats.Biff.Tokens
{
    internal sealed class AreaNToken : AreaTokenBase
    {
        public AreaNToken(AccessorType type)
            : base(type)
        {
        }
        public AreaNToken(AccessorType type, RgceAreaRel rgceAreaRel)
            : this(type)
        {
            this._rgceAreaRel = rgceAreaRel;
        }
        private RgceAreaRel _rgceAreaRel;


        public override FormulaTokenId TokenId
        {
            get { 
                switch (_type)
                {
                    case AccessorType.Array:
                        return FormulaTokenId.AreaNA;
                        case AccessorType.Reference:
                        return FormulaTokenId.AreaN;
                        case AccessorType.Value:
                        return FormulaTokenId.AreaNV;
                    default: throw new NotSupportedException();
                }
            }
        }

        internal override void ReadContent(FormulaReadContext context)
        {
            this._rgceAreaRel.Read(context.Reader);
        }

        internal override Expression GetExpression(FormulaEvaluationContext context)
        {
            if (context.Target == null)
                throw new InvalidFormulaException();
            Contract.Assert(context.Target != null);
            Cell cell = context.Target;
            RangeReference rr = new MultiCellsRangeReference(
                ToReferenceRelative(_rgceAreaRel.FirstRowIndex, _rgceAreaRel.FirstColumnIndex, _rgceAreaRel.IsFirstRowRelative, _rgceAreaRel.IsFirstColumnRelative, cell),
                ToReferenceRelative(_rgceAreaRel.LastRowIndex, _rgceAreaRel.LastColumnIndex, _rgceAreaRel.IsLastRowRelative, _rgceAreaRel.IsLastColumnRelative, cell));            
           return new RangeReferenceExpression(rr, context.Worksheet);
        }
        internal CellReference ToReferenceRelative(int rowIndex, int columnIndex, bool isRowRelative, bool isColumnRelative, Cell cell)
        {
            Contract.Requires(cell != null);
            Worksheet ws = cell.Worksheet;
           /* return new StaticCellReference(
                new FloatingRowReference(ws, rowIndex, !isRowRelative),
                new FloatingColumnReference(ws, columnIndex, !isColumnRelative)
                );
            */
            return new StaticCellReference(
                new AnchoredRowReference(!isRowRelative? ws.Rows[rowIndex] : ws.Rows[cell.Row.Index + rowIndex], !isRowRelative),
                new AnchoredColumnReference(
                    !isColumnRelative ? ws.Columns[columnIndex] : ws.Columns[cell.Column.Index + columnIndex], !isColumnRelative));
             
        }


        public override void WriteContent(FormulaWriteContext context)
        {
            this._rgceAreaRel.Write(context.Writer);
        }
    }
}